﻿using System;
using GpgCore.Corporations;
using GpgCore.Maps;
using GpgCore.Products;

namespace GpgCore.MapItems
{
    public class Factory : MapItem
    {
        public FactoryScheme Scheme;
        public float ActualWorkers;
        public int NeedWorkers
        {
            get { return Scheme.WorkersPerLevel*Level; }
        }

        public Corporation OwnCorporation;
        public CityOffice OwnOffice
        {
            get
            {
                if (BelongsToCity == null)
                    return null;
                CityOffice result;
                return BelongsToCity.CityOffices.TryGetValue(OwnCorporation, out result) ? result : null;
            }
        }

        public Product SourceProd1;
        public Product SourceProd2;
        public Product SourceProd3;

        public int Level = 1;
        public double Productivity;
        public double WorkerPayment;

        public Factory(PlanetMapCell mapCell, FactoryScheme scheme, Corporation ownCorporation) : base(mapCell)
        {
            OwnCorporation = ownCorporation;
            Scheme = scheme;
            ItemType = MapItemType.Factory;

            SourceProd1 = new Product(Scheme.InputProduct1, 0);
            SourceProd2 = new Product(Scheme.InputProduct2, 0);
            SourceProd3 = new Product(Scheme.InputProduct3, 0);

            OwnOffice.Factories.AddDistinct(this);
        }

        public override void StartNextTurn()
        {
            HireWorkers();
            base.StartNextTurn();
        }
        public override void EndNextTurn()
        {
            GetMyWorkers();
            CalcProductivity();
            DoFactoring();
            base.EndNextTurn();
        }

        private void GetMyWorkers()
        {
            ActualWorkers = (float) BelongsToCity.Exchanges[ProductType.Employees].GetMyProduct(this);
        }
        private void DoFactoring()
        {
            var s1Need = Scheme.InputProdCountPerWorker1*Scheme.WorkersPerLevel*Level*Productivity;
            var s2Need = Scheme.InputProdCountPerWorker2*Scheme.WorkersPerLevel*Level*Productivity;
            var s3Need = Scheme.InputProdCountPerWorker3*Scheme.WorkersPerLevel*Level*Productivity;

            //get source1
            var s1Demand = s1Need - SourceProd1.Count;
            if (s1Demand > 0)
                SourceProd1.Count += OwnOffice.Warehouse.ExtractProduct(s1Demand, SourceProd1.ProdType);
            //get source2
            if (SourceProd2.ProdType != ProductType.None)
            {
                var s2Demand = s2Need - SourceProd2.Count;
                if (s2Demand > 0)
                    SourceProd2.Count += OwnOffice.Warehouse.ExtractProduct(s2Demand, SourceProd2.ProdType);
            }
            //get source3
            if (SourceProd3.ProdType != ProductType.None)
            {
                var s3Demand = s3Need - SourceProd3.Count;
                if (s3Demand > 0)
                    SourceProd3.Count += OwnOffice.Warehouse.ExtractProduct(s3Demand, SourceProd3.ProdType);
            }

            var s1Part = SourceProd1.Count/s1Need;
            var s2Part = s2Need > 0 ? SourceProd2.Count/s2Need : 0;
            var s3Part = s3Need > 0 ? SourceProd3.Count/s3Need : 0;

            var sPart = SourceProd2.ProdType != ProductType.None ? Math.Min(s1Part, s2Part) : s1Part;
            sPart = SourceProd3.ProdType != ProductType.None ? Math.Min(sPart, s3Part) : sPart;
            if (sPart > 1)
                sPart = 1;

            Productivity = Math.Min(Productivity, sPart);

            var outputProdCount = Scheme.OutputProdCountPerWorker * Level * Scheme.WorkersPerLevel * Productivity;

            SourceProd1.Count -= (long)(s1Need*Productivity);
            SourceProd2.Count -= (long)(s2Need*Productivity);
            SourceProd3.Count -= (long)(s3Need*Productivity);

            OwnOffice.Warehouse.Products[Scheme.OutputProduct].Count += (long) outputProdCount;
        }
        private void CalcProductivity()
        {
            Productivity = ActualWorkers/NeedWorkers;
            Productivity = Math.Min(Productivity, 2);
        }
        private void HireWorkers()
        {
            double payment = WorkerPayment*NeedWorkers;
            payment = OwnOffice.ExtractMoney(payment);
            BelongsToCity.Exchanges[ProductType.Employees].OpenPositionWithMoney(payment, this);
        }
    }
}
